"""
Django中间件

- 菜鸟教程: https://www.runoob.com/django/django-middleware.html
"""


from django.utils.deprecation import MiddlewareMixin
from bddjango import my_api_assert_function, APIResponse
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from bddjango import add_status_and_msg

res_map = {
    # 'status': 'code',
    # 'result': 'data',

    'code': 'status',
    'data': 'result',
}


class UniResponseFormat(MiddlewareMixin):
    """
    统一返回格式
    """

    def process_response(self, request, response):
        if hasattr(response, 'data'):
            data = response.data

            change_times = 0
            for k, v in res_map.items():
                if k in data:
                    data[v] = data.pop(k)
                    change_times += 1
            if change_times:
                response._is_rendered = False
                response.render()
            return response
        else:
            return response


class ClientException(MiddlewareMixin):
    """
    处理psql的idle链接问题

    - 解决方案:
        - 关闭旧链接(本方案)
        - 单线程运行(影响性能)
            ```
            python manage.py runserver --nothreading
            ```
        - 使用`gunicorn`部署
    """

    def process_exception(self, request, exception):  # 引发错误 才会触发这个方法
        e_str = str(exception)
        if 'client' in e_str:
            msg = f'Error! {e_str}'
            msg += '! 可能出现postgresql的idle链接状况?'

            from django.db import close_old_connections
            from django.db import connection
            close_old_connections()
            with connection.cursor() as cursor:
                # 关闭旧idle连接方案
                sql = "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle'"
                cursor.execute(sql)
                row = cursor.fetchall()
                print(sql)
                print(row)

            ret = {
                'code': 404,
                'msg': e_str,
                'data': None,
            }
            return JsonResponse(ret)


class UniExceptionFormat(MiddlewareMixin):
    """
    统一assert引起的Exception的返回格式
    """

    def process_exception(self, request, exception):  # 引发错误 才会触发这个方法
        e_str = str(exception)
        e_type = exception.__class__.__name__
        if e_type == 'AssertionError':
            status = 404
            msg = e_type + ': ' + str(e_str)
            ret = {
                'code': status,
                'msg': msg,
                'data': None,
            }
            return JsonResponse(ret)